package main

import (
    "crypto/sha256"
    "database/sql"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "hash/fnv"
    "log"
    "net/http"
    "os/exec"
    "strconv"
    "strings"
    "time"

    "github.com/gorilla/mux"
    _ "github.com/mattn/go-sqlite3"
)

type Card struct {
    ID      int    `json:"id"`
    Title   string `json:"title"`
    Content string `json:"content"`
}

func initDB() *sql.DB {
    db, err := sql.Open("sqlite3", "./cards.db")
    if err != nil {
        log.Fatal(err)
    }
    createTableSQL := `CREATE TABLE IF NOT EXISTS cards (
		"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,		
		"title" TEXT,
		"content" TEXT
	);`
    if _, err := db.Exec(createTableSQL); err != nil {
        log.Fatal(err)
    }
    return db
}

func main() {
    db := initDB()
    defer db.Close()

    router := mux.NewRouter()

    apiRouter := router.PathPrefix("/api/v1").Subrouter()

    // 卡片创建
    cardRouter := apiRouter.PathPrefix("/card").Subrouter()
    cardRouter.HandleFunc("/one", getCard(db)).Methods("POST")       // 单条数据
    cardRouter.HandleFunc("/gets", getCards(db)).Methods("GET")      // 全部数据
    cardRouter.HandleFunc("/create", createCard(db)).Methods("POST") // 创建卡片
    cardRouter.HandleFunc("/update", updateCard(db)).Methods("PUT")  // 更新卡片
    cardRouter.HandleFunc("/delete", deleteCard(db)).Methods("POST") // 删除卡片

    // 登录鉴权
    authRouter := apiRouter.PathPrefix("/user").Subrouter()
    authRouter.HandleFunc("/login", loginUser).Methods("POST")
    authRouter.HandleFunc("/logout", logoutUser).Methods("POST")

    // 代码解释器
    langRouter := apiRouter.PathPrefix("/interpreter").Subrouter()
    langRouter.HandleFunc("/python", runPythonCode).Methods("POST")

    http.Handle("/", router)
    corsRouter := enableCORS(router)

    log.Println("Server started on: http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", corsRouter))
}

func loginUser(w http.ResponseWriter, r *http.Request) {
    userInfo := &struct {
        UserName string
        PassWord string
    }{}
    if err := json.NewDecoder(r.Body).Decode(&userInfo); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // If login successful, you can respond with a token or other data
    if userInfo.UserName == "admin" && userInfo.PassWord == "admin" {
        hashString := func(input string) string {
            // 使用 SHA-256 进行哈希
            hasher := sha256.New()
            timestamp := strconv.Itoa(int(time.Now().Unix()))
            hasher.Write([]byte(input + timestamp))
            hashedBytes := hasher.Sum(nil)

            // 将哈希结果转换为十六进制字符串
            hashedString := hex.EncodeToString(hashedBytes)

            return hashedString
        }(userInfo.UserName + userInfo.PassWord)
        // Example response for success:
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]interface{}{"token": hashString})
        fmt.Println("成功!")
    } else {
        // Example response for failure:
        http.Error(w, "Login failed", http.StatusUnauthorized)
        fmt.Println("失败!")
    }
}

func logoutUser(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]any{
        "msg":  "退出成功",
        "code": 200,
    })
}

type CodeBlock struct {
    Language string `json:"language"`
    Content  string `json:"content"`
}

type CodeBlocksRequest struct {
    CodeBlocks []CodeBlock `json:"codeBlocks"`
}

func runPythonCode(w http.ResponseWriter, r *http.Request) {
    var request CodeBlocksRequest

    err := json.NewDecoder(r.Body).Decode(&request)
    if err != nil {
        http.Error(w, "Invalid JSON payload", http.StatusBadRequest)
        return
    }

    // 执行Python代码块
    results := executePythonCodeBlocks(request.CodeBlocks)

    // 返回结果
    json.NewEncoder(w).Encode(results)
}

func executePythonCodeBlocks(codeBlocks []CodeBlock) []string {
    var results []string

    for _, block := range codeBlocks {
        if block.Language == "python" {
            result, err := executePythonCode(block.Content)
            if err != nil {
                results = append(results, fmt.Sprintf("Error executing code: %v", err))
            } else {
                results = append(results, result)
            }
        } else {
            results = append(results, fmt.Sprintf("Unsupported language: %s", block.Language))
        }
    }

    return results
}

func executePythonCode(code string) (string, error) {
    cmd := exec.Command("python", "-c", code)

    output, err := cmd.CombinedOutput()
    if err != nil {
        return "", err
    }

    return strings.TrimSpace(string(output)), nil
}

// 跨域请求
func enableCORS(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Set headers to allow CORS
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

        // Check for preflight requests
        if r.Method == "OPTIONS" {
            // Send response to preflight requests
            w.WriteHeader(http.StatusOK)
            return
        }

        // Pass down the request to the next handler
        next.ServeHTTP(w, r)
    })
}

func getCards(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var cards []Card
        rows, err := db.Query("SELECT * FROM cards")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        defer rows.Close()

        for rows.Next() {
            var card Card
            if err := rows.Scan(&card.ID, &card.Title, &card.Content); err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
            cards = append(cards, card)
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(cards)
    }
}

func getCard(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var card Card
        if err := json.NewDecoder(r.Body).Decode(&card); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        err := db.QueryRow("SELECT * FROM cards WHERE id = ?", card.ID).Scan(&card.ID, &card.Title, &card.Content)
        if err != nil {
            if err == sql.ErrNoRows {
                http.NotFound(w, r)
                return
            }
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(card)
    }
}

func createCard(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var card Card
        if err := json.NewDecoder(r.Body).Decode(&card); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        // Generate a unique hash value based on the current timestamp
        timestamp := time.Now().Unix()
        // hashID generates a hash value based on the provided integer id.
        hashID := func(id int64) int {
            h := fnv.New32a()
            _, _ = h.Write([]byte(strconv.FormatInt(id, 10)))
            return int(h.Sum32())
        }(timestamp)

        // Omitting the id field to let the database handle auto-increment
        _, err := db.Exec("INSERT INTO cards (id, title, content) VALUES (?, ?, ?)", hashID, card.Title, card.Content)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        card.ID = hashID
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(card)
    }
}

func updateCard(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        var card Card
        if err := json.NewDecoder(r.Body).Decode(&card); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        _, err := db.Exec("UPDATE cards SET title = ?, content = ? WHERE id = ?", card.Title, card.Content, card.ID)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(card)
    }
}

func deleteCard(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        var card Card
        if err := json.NewDecoder(r.Body).Decode(&card); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        _, err := db.Exec("DELETE FROM cards WHERE id = ?", card.ID)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        w.WriteHeader(http.StatusOK)
    }
}
